/**
 * 
 */
package com.duowan.cms.service.channel;

import java.io.File;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.duowan.cms.common.domain.Page;
import com.duowan.cms.common.exception.BaseCheckedException;
import com.duowan.cms.common.service.DoToDtoConvertorFactory;
import com.duowan.cms.common.util.IdManager;
import com.duowan.cms.common.util.SystemCommandUtil;
import com.duowan.cms.common.util.ThreadUtil;
import com.duowan.cms.common.webapp.property.ExtendedPropertyPlaceholderConfigurer.PropertiesHolder;
import com.duowan.cms.core.rmi.client.channel.ChannelRemoteService;
import com.duowan.cms.domain.article.rpst.Article4TagListRepository;
import com.duowan.cms.domain.article.rpst.ArticleRepository;
import com.duowan.cms.domain.channel.Channel;
import com.duowan.cms.domain.channel.rpst.ChannelRepository;
import com.duowan.cms.domain.tag.Tag;
import com.duowan.cms.domain.tag.rpst.TagRepository;
import com.duowan.cms.domain.user.UserPower;
import com.duowan.cms.domain.user.rpst.UserPowerRepository;
import com.duowan.cms.domain.user.rpst.UserRepository;
import com.duowan.cms.dto.channel.ChannelInfo;
import com.duowan.cms.dto.channel.ChannelSearchCriteria;
import com.duowan.cms.dto.tag.TagCategory;
import com.duowan.cms.dto.user.UserInfo;
import com.duowan.cms.dto.user.UserPowerInfo;
import com.duowan.cms.dto.user.UserRole;
import com.duowan.cms.dto.user.UserSearchCriteria;
import com.duowan.cms.intf.comment3.Comment3RemoteService;
import com.duowan.cms.parser.rmi.client.dir.DirRemoteService;

@Service("channelService")
public class ChannelServiceImpl implements ChannelService, ChannelRemoteService {

    //为开专区创建目录
    private final static String MKDIR_FOR_CHANNEL = PropertiesHolder.get("mkdir4ChannelScriptFile");
    
    //专区上下线
    private final static String UP_ON_LINE = PropertiesHolder.get("upOnlineChannelScriptFile");
    
    @Autowired
    private ChannelRepository channelRepository;

    @Autowired
    private ArticleRepository articleRepository;// 用于创建article_${channelId}表

    @Autowired
    private Article4TagListRepository article4TagListRepository;// 用于创建list_${channelId}表

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private UserPowerRepository userPowerRepository;
    
    @Autowired
    private TagRepository tagRepository;
    
    @Autowired
    private DirRemoteService dirRemoteService;
    
    @Autowired
    private Comment3RemoteService comment3RemoteService;

    @Override
    public ChannelInfo getById(String id) {
        Channel channel = channelRepository.getById(id);
        return (ChannelInfo) DoToDtoConvertorFactory.getConvertor(Channel.class).do2Dto(channel);
    }

    @Override
    public ChannelInfo getByName(String cname) {
        Channel channel = channelRepository.getByName(cname);
        if (channel != null)
            return (ChannelInfo) DoToDtoConvertorFactory.getConvertor(Channel.class).do2Dto(channel);
        return null;
    }

    @Override
    public List<ChannelInfo> getAllChannel() {
        return channelRepository.getAll();
    }

    @Override
    public Page<ChannelInfo> pageSearch(ChannelSearchCriteria searchCriteria) {
        return channelRepository.pageSearch(searchCriteria);
    }

    @Override
    public void openNewChannel(ChannelInfo channelInfo, String logoPath) throws Exception {
        String channelId = channelInfo.getId();
        Channel channel = new Channel(channelInfo);
        
        logger.info("1.准备开专区(channelId="+channel.getId()+")。");
        // 1.增加channel表记录
        channelRepository.save(channel);
        // 2.创建article_${channelId}表
        articleRepository.createTableByChannelId(channelId);

        // 3.创建list_${channelId}表
        article4TagListRepository.createTableByChannelId(channelId);
        logger.info("2.开专区(channelId="+channel.getId()+")建表成功。");
        
        // 4.向userpower插入管理员在新专区的权限
        List<UserInfo> admins = getSystemAdmins();// 得到所有系统管理员
        userPowerRepository.saveList(generateAdminPowerInChannel(admins, channel));// 插入管理员权限
        logger.info("3.开专区(channelId="+channelId+")，管理员权限分配成功。");
        
        // 5.增加特殊标签到频道
        for(String tagName : Tag.DEFAULT_SPECIAL_TAGS){
            Tag tag = generateTagInChannel(tagName, channel);
            tagRepository.save(tag);
        }
        logger.info("4.开专区(channelId="+channelId+")，增加特殊标签成功。");
        
        //6.在“前端机器”和“模板机器”创建目录
        this.mkdir4NewChannel(channelId);
        logger.info("5.开专区(channelId="+channelId+")，在前端机器和模板机器创建目录成功。");
        
        //7.复制logo
        try{
            copyLogo(logoPath, channel.getArticleFilePath());
            logger.info("6.复制网站logo成功:" + logoPath + "-->" + channel.getArticleFilePath());
        }catch(Exception e){
            logger.warn("图标复制不成功：favicon.ico", e);
        }
        
        // 8.处理是否上线
        if (channelInfo.isUpline()) {
            upline(channelInfo);
            logger.info("7.开专区(channelId="+channelId+")，并且切出外网成功。");
        }
        
        //9.开通通用评论(异步)
        final ChannelInfo channelInfo2 = channelInfo;
        ThreadUtil.getThreadPool().execute(new Runnable(){
            @Override
            public void run() {
                comment3RemoteService.openCommentSite(channelInfo2);
            }
        });
        
    }
    
    private void copyLogo(String logoPath, String basePath) throws Exception{
        String ico = "favicon.ico";
        if(!basePath.endsWith("/")){
            basePath += "/";
        }
        FileUtils.copyFile(new File(logoPath), new File(basePath + ico));
    }
    
    private Tag generateTagInChannel(String tagName, Channel channel){
        
        Tag tag = new Tag();
        tag.setName(tagName);
        tag.setChannel(channel);
        tag.setParentName("");
        tag.setTree("," + tagName + ",");
        tag.setUpdateTime(new Date());
        tag.setCategory(TagCategory.SPECIAL.getValue());
        tag.setId(IdManager.generateId());
        
        return tag;
    }
    
    @Override
    public void addMainEditorToNewChannel(List<UserInfo> mainEditors, ChannelInfo newchannelInfo, String adminId) throws BaseCheckedException {

        // 生成userPower对象入库
        userPowerRepository.saveList(generateMainEditorPowerInChannel(mainEditors, new Channel(newchannelInfo), adminId));

    }

    @Override
    public void upline(ChannelInfo channelInfo) throws Exception {
        // 1.更新数据库
        Channel channel = channelRepository.getById(channelInfo.getId());
        channel.setUpline(true);
        channelRepository.update(channel);

        // 2.执行上线脚本
        SystemCommandUtil.exec(UP_ON_LINE + " start " + channel.getId());
    }

    @Override
    public void downline(ChannelInfo channelInfo) throws Exception {
        // 1.更新数据库
        Channel channel = channelRepository.getById(channelInfo.getId());
        channel.setUpline(false);
        channelRepository.update(channel);

        // 2.执行下线脚本
        SystemCommandUtil.exec(UP_ON_LINE + " stop " + channel.getId());
    }
    
    private void mkdir4NewChannel(String channelId) throws Exception {
        //在前端机器创建目录
        SystemCommandUtil.exec(MKDIR_FOR_CHANNEL +" "  + channelId);
        logger.info("开专区(channelId="+channelId+")，在前端机器建目录成功。");
        dirRemoteService.mkdir4NewChannel(channelId);
        logger.info("开专区(channelId="+channelId+")，在模板机器建目录成功。");
        
    }

    private List<UserInfo> getSystemAdmins() {
        UserSearchCriteria searchCriteria = new UserSearchCriteria();
        searchCriteria.setPageSize(null);
        searchCriteria.setAdmin(true);
        return userRepository.listSearch(searchCriteria);
    }

    private List<UserPower> generateAdminPowerInChannel(List<UserInfo> admins, Channel channel) {
        return generateRolePowerInChannel(admins, channel, UserRole.ADMINISTRATOR, null);
    }

    private List<UserPower> generateMainEditorPowerInChannel(List<UserInfo> mainEditors, Channel channel, String adminId) {
        return generateRolePowerInChannel(mainEditors, channel, UserRole.MAIN_EDITOR, adminId);
    }

    private List<UserPower> generateRolePowerInChannel(List<UserInfo> roles, Channel channel, UserRole userRole, String adminId) {
        List<UserPower> userPowers = new ArrayList<UserPower>();
        Date now = new Date();
        for (UserInfo u : roles) {
            UserPower up = new UserPower();
            up.setUserId(u.getUserId());
            up.setAdminId(adminId);
            up.setChannel(channel);
            up.setCreateTime(now);
            up.setLastModifyTime(now);
            up.setValue(userRole.getValue() + userRole.getExactValue());
            userPowers.add(up);
        }
        return userPowers;
    }

    @Override
    public void important(String channelId) {
        // .更新数据库
        Channel channel = channelRepository.getById(channelId);
        if(null != channel){
            channel.setImportant(true);
            channelRepository.update(channel);
        }
    }

    @Override
    public void unimportant(String channelId) {
        // 更新数据库
        Channel channel = channelRepository.getById(channelId);
        if(null != channel){
            channel.setImportant(false);
            channelRepository.update(channel);
        }
    }
    
    @Override
    public void updateChannelInfo(ChannelInfo channelInfo) {
        Channel channel = channelRepository.getById(channelInfo.getId());
        if(null != channel){
            channelRepository.update(channel.update(channelInfo));
        }
    }

	@Override
	public List<ChannelInfo> getChannelByUserId(String userId) {
	    List<ChannelInfo> channelInfos = new ArrayList<ChannelInfo>();
	    List<UserPowerInfo> userPowerInfos =  userPowerRepository.getAllPowerByUserId(userId);
	    if(!userPowerInfos.isEmpty()){
	        for(int i=0; i<userPowerInfos.size(); i++){
	            channelInfos.add(userPowerInfos.get(i).getChannelInfo());
	        }
	    }
	    return channelInfos;
	}
    
    

}
